<script setup lang="ts">
import { AsideInstance, ElMessage, ElNotification } from 'element-plus';
import { computed, inject, nextTick, onMounted, provide, reactive, ref, shallowRef } from 'vue';
import VerticalResizerVue from '../../components/VerticalResizer.vue';
import HorizontalResizer from '../../components/HorizontalResizer.vue';
import TransactionTreeVue from './TransactionTree.vue';
import MessageTreeVue from './MessageTree.vue';
import { SMLFile, ConnectionOptions, LogOutput, MessageTransaction, Preference } from '../../common/types';
import { open, save } from '@tauri-apps/plugin-dialog';
import { ConnectionStatus, HSMSMode, IconStaus, Secs1Mode, SecsProtocol } from '../../common/enums';
import Circle1Vue from '../../components/Circle-1.vue';
import LogVue from "./Log.vue";
import helper from '../../common/helpler';
import { secsService, smlService } from '../../common/api';
import i18n from '../../common/i18n';

const props = defineProps<{ globalId: number }>();

const aside = shallowRef<AsideInstance>();
const leftAside = shallowRef();
const transactionTree = shallowRef();
const appLog = shallowRef();
const messageTree = shallowRef();
const outputMaxSize = ref(2000);
const messageMaxSize = ref(2000);
const setTabLabel = inject<(id: number, label: string) => {}>("setTabLabel");
const editOptionsImpl = inject<() => {}>("editOptions");

const data = reactive({
    smlPath: "",
    ip: "127.0.0.1",
    mode: "",
    port: 5000,
    iconStatus: IconStaus.Error,
    connectionStatus: ConnectionStatus.Initial,
    isOpen: 0,
    identity: ""
});

const connectionStatusText = computed(() => {
    return helper.getConnectionStatusText(data.connectionStatus);
});

const loadLibrary = (sml: SMLFile) => {
    data.smlPath = sml.path;;
    setConfiguration(sml.configuration);
    transactionTree.value.load(sml.transactions);
}

const onVerticalResized = (width: number) => {
    let el = aside.value?.$el;
    el.style.width = (width + 5) + "px";
    leftAside.value.style.width = width + "px";
}

const onHorizontalResized = (top: number) => {
    appLog.value.$el.style.height = (appLog.value.$el.parentNode.offsetHeight - top - 5) + "px";
}
const smlLoad = async (isRefresh: boolean) => {
    let path = null;
    if (isRefresh) {
        path = data.smlPath
    }
    else {
        path = await open({ multiple: false, filters: [] });
    }
    if (path == null) {
        return;
    }
    smlService.load(props.globalId, path).then(res => {
        loadLibrary(res);
    }).catch(err => {
        console.error(err);
    });
}

provide("smlLoad", smlLoad);

const setConfiguration = (configuration: ConnectionOptions) => {
    data.identity = configuration.identity;
    nextTick(() => {
        setTabLabel && setTabLabel(props.globalId, configuration.identity);
    });
    if (configuration.protocol == SecsProtocol.HSMS) {
        if (configuration.hsms != null) {
            if (configuration.hsms.mode == HSMSMode.Active) {
                data.mode = "Active";
                data.port = configuration.hsms.remotePort;
                data.ip = configuration.hsms.remoteIp;
            }
            else {
                data.mode = "Passive";
                data.port = configuration.hsms.localPort;
                data.ip = configuration.hsms.localIp;
            }
        }
    }
    else {
        if (configuration.secs1 != null) {
            if (configuration.secs1.mode == Secs1Mode.COM) {
                data.mode = "COM";
                data.ip = configuration.secs1.com;
                data.port = -1;
            }
            else {
                data.mode = "TCP/IP";
                data.ip = configuration.secs1.ip;
                data.port = configuration.secs1.port;
            }
        }
    }
}

const setPreference = (data: Preference) => {
    messageMaxSize.value = data.log.messageMaxSize;
    outputMaxSize.value = data.log.outputMaxSize;
}

const editOptions = () => {
    editOptionsImpl && editOptionsImpl();
}

const sendPrimaryMessage = (txId: string) => {
    secsService.send_primary(props.globalId, txId).then(res => {
        if (res != null) {
            messageTree.value.appendSecondaryMessage(res.time, res.message);
        }
    }).catch(err => {
        console.error(err);
    })
}

const changeConnection = () => {
    if (data.isOpen == 0) {
        data.isOpen = 2;
        secsService.connect(props.globalId).then(_ => {
            data.isOpen = 1;
        });
    }
    else if (data.isOpen == 1) {
        data.isOpen = 2;
        secsService.shutdown(props.globalId).then(_ => {
            data.isOpen = 0;
        });
    }
}

const appendLog = (entity: LogOutput) => {
    appLog.value.appendLog(entity);
}

const setConnectionStatus = (status: ConnectionStatus) => {
    data.connectionStatus = status;
    if (status == ConnectionStatus.Selected) {
        data.iconStatus = IconStaus.Success;
    }
    else if (status == ConnectionStatus.Initial || status == ConnectionStatus.Disconnected || status == ConnectionStatus.Shutdown) {
        data.iconStatus = IconStaus.Error;
    }
    else {
        data.iconStatus = IconStaus.Warning;
    }
}

onMounted(() => {
    nextTick(() => {
        smlService.load(props.globalId, null).then(res => {
            loadLibrary(res);
        }).catch(err => {
            ElNotification.error(err as any);
        });
    })

})

const getTransactionTree = () => {
    return transactionTree.value;
}

const getMessageTree = () => {
    return messageTree.value;
}

const isOpen = (): boolean => {
    return data.isOpen != 0;
}

const saveSML = async (isSaveAs: boolean) => {
    let filePath;
    if (isSaveAs) {
        let tPath = data.smlPath;
        /// @ts-ignore
        let c = (window.navigator.userAgentData && window.navigator.userAgentData.platform != "Windows") ? "/" : "\\";
        let lIndex = tPath.lastIndexOf(c);
        if (lIndex > -1) {
            tPath = tPath.substring(0, lIndex) + c + data.identity + ".json";
        }
        filePath = await save({
            title: "Save SML File",
            defaultPath: tPath,
            filters: []
        });
    }
    else {
        filePath = data.smlPath;
    }
    if (filePath == null) {
        return;
    }
    smlService.save(props.globalId, filePath).then(_ => {
        ElMessage.success({
            plain: true,
            message: "Saved",
        });
    }).catch(err => {
        ElMessage.error({
            plain: true,
            message: err.toString(),
        });
    })
}

provide("newTransaction", (transaction: MessageTransaction) => {
    transactionTree.value.newTransaction(transaction);
})

defineExpose({ setConfiguration, appendLog, setConnectionStatus, getTransactionTree, isOpen, getMessageTree, saveSML, setPreference })

</script>
<template>
    <el-container>
        <el-container @keydown="">
            <el-aside ref="aside" width="340px">
                <div ref="leftAside"
                    style="float: left;width: 335px;height: 100%;display: flex;flex-direction: column;">
                    <div class="app-toolbar-1" style="text-align: center;flex-grow: 0;user-select: none">
                        Transactions
                    </div>
                    <TransactionTreeVue @save="saveSML" ref="transactionTree" :connection-status="data.connectionStatus"
                        :global-id="props.globalId" @send-primary-message="sendPrimaryMessage">
                    </TransactionTreeVue>
                </div>
                <VerticalResizerVue style="float:left;width:5px;height: 100%;" @resized="onVerticalResized">
                </VerticalResizerVue>
            </el-aside>
            <el-main class="no-padding" style="float: left;display: flex;flex-direction: column;position: relative;">
                <div class="app-toolbar-1" style="text-align: center;user-select: none;flex-grow: 0;flex-shrink: 0;">
                    Messages
                </div>
                <MessageTreeVue ref="messageTree" :max-size="messageMaxSize"
                    style="flex-grow: 1; overflow-x: hidden;overflow-y: auto;">
                </MessageTreeVue>
                <HorizontalResizer style="flex-grow: 0;flex-shrink: 0;" @resized="onHorizontalResized">
                </HorizontalResizer>
                <LogVue ref="appLog" :max-size="outputMaxSize"
                    style="flex-grow: 0; flex-shrink: 0; height: 180px;overflow-x:hidden ;overflow-y: auto;"></LogVue>
            </el-main>
        </el-container>
        <el-footer height="32px"
            style="background-color:var(--color-deep-1);cursor:default;color:var(--color-white); display: flex;align-items: center; justify-content: space-between; padding:0px 10px 0px 10px;">
            <div
                style="flex-grow: 1; white-space: nowrap; word-break:keep-all; overflow: hidden; text-overflow: ellipsis;user-select: none;">
                {{ data.smlPath }}
                <el-link @click="smlLoad(true)" style="color:var(--color-light-2);margin-left: 10px;">{{
                    i18n.global.t("refresh") }}</el-link>
                <el-link @click="smlLoad(false)" style="color:var(--color-light-2);margin-left: 10px;">{{
                    i18n.global.t("reload") }}</el-link>
            </div>
            <div class="conn-options" @click="editOptions">
                <span>{{ data.mode }}</span>
                <span style="margin-left:5px">{{ data.ip }}</span>
                <span v-show="data.port >= 0">:{{ data.port }}</span>
            </div>
            <div style="padding:3px 0px 0px 8px;cursor: pointer;flex-grow: 0;flex-shrink: 0;" @click="changeConnection">
                <Circle1Vue :status="data.iconStatus"></Circle1Vue>
            </div>
            <div
                style="padding:0px 0px 0px 8px;cursor: default;flex-grow: 0;width:90px;flex-shrink: 0; user-select: none;">
                {{ connectionStatusText }}
            </div>
        </el-footer>
    </el-container>
</template>